using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.Win32;
using WeiboPlus.Models;

namespace WeiboPlus.Service.Web
{
    public delegate void AsyncHttpCallback(AsyncHttp http, string content);

    class RequestState
    {
        public const int BUFFER_SIZE = 1024;
        public byte[] BufferRead;
        public StringBuilder requestData;

        public HttpWebRequest request;
        //public HttpWebResponse response;
        public Stream streamResponse;

        public byte[] PostData;
        //public Stream PostStream;

        public AsyncHttpCallback cb;

        public RequestState()
        {
            BufferRead = new byte[BUFFER_SIZE];
            requestData = new StringBuilder("");
            request = null;
            streamResponse = null;
            cb = null;
        }
    }

    public class AsyncHttp
    {
        public ManualResetEvent allDone = new ManualResetEvent(false);
        const int DefaultTimeout = 60 * 1000; // 1 minutes timeout

        public bool HttpPost(string url, string queryString, AsyncHttpCallback callback)
        {
            StreamWriter requestWriter = null;

            HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
            webRequest.Method = "POST";
            webRequest.ContentType = "application/x-www-form-urlencoded";
            //webRequest.ServicePoint.Expect100Continue = false;

            try
            {
                RequestState state = new RequestState();
                state.cb = callback;
                state.request = webRequest;
                state.PostData = Encoding.UTF8.GetBytes(queryString);

                webRequest.BeginGetRequestStream(GetRequestStreamCallback, state);

                allDone.WaitOne();
            }
            catch
            {
                return false;
            }
            finally
            {
                if (requestWriter != null)
                {
                    requestWriter.Close();
                    requestWriter = null;
                }
            }

            return true;
        }

        private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
        {
            RequestState state = (RequestState)asynchronousResult.AsyncState;

            HttpWebRequest request = state.request;

            // End the operation
            Stream postStream = request.EndGetRequestStream(asynchronousResult);

            // Write to the request stream.
            if (state.PostData != null && state.PostData.Length > 0)
            {
                postStream.Write(state.PostData, 0, state.PostData.Length);

                var str = System.Text.Encoding.UTF8.GetString(state.PostData, 0, state.PostData.Length);
                Debug.WriteLine(str);
            }

            //if (state.PostStream != null && state.PostStream.Length > 0)
            //{
            //    state.PostStream.Position = 0;
            //    byte[] tempBuffer = new byte[state.PostStream.Length];
            //    state.PostStream.Read(tempBuffer, 0, tempBuffer.Length);
            //    state.PostStream.Close();
            //    postStream.Write(tempBuffer, 0, tempBuffer.Length);
            //}
            postStream.Close();
            postStream = null;
            // Start the asynchronous operation to get the response
            request.BeginGetResponse(new AsyncCallback(GetResponseCallback), state);


        }

        private void GetResponseCallback(IAsyncResult asynchronousResult)
        {
            RequestState state = (RequestState)asynchronousResult.AsyncState;

            try
            {
                HttpWebRequest webRequest = state.request;
                WebResponse response = webRequest.EndGetResponse(asynchronousResult);

                // Read the response into a Stream object.
                Stream streamResponse = response.GetResponseStream();
                StreamReader streamRead = new StreamReader(streamResponse);
                state.requestData.Append(streamRead.ReadToEnd());
                FireCallback(state);
                return;
            }
            catch (WebException ex)
            {
                //fire back
                state.requestData.Append(ex.Message);
                FireCallback(state);
            }
            finally
            {
                allDone.Set();
            }

        }

        public bool HttpPostWithFile(string url, string queryString, List<SNSParameter> files, AsyncHttpCallback callback, List<SNSParameter> listParam = null)
        {
            //Stream requestStream = null;
            string boundary = "sdfjksdfjsflsdjslfkjdjls";
            // DateTime.Now.Ticks.ToString("x");

            //if (!string.IsNullOrEmpty(queryString))
            //    url += '?' + queryString;
            HttpWebRequest webRequest = WebRequest.Create(url) as HttpWebRequest;
            //webRequest.ServicePoint.Expect100Continue = true;
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
            webRequest.Method = "POST";


            //webRequest.Credentials = CredentialCache.DefaultCredentials;

            try
            {

                using (Stream memStream = new MemoryStream())
                {
                    byte[] boundarybytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary);
                    byte[] newlinebytes = System.Text.Encoding.UTF8.GetBytes("\r\n");
                    string formdataTemplate = "\r\n--" + boundary + "\r\n\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                    if (listParam == null)
                        listParam = HttpUtil.GetQueryParameters(queryString);

                    foreach (SNSParameter param in listParam)
                    {
                        string formitem = string.Format(formdataTemplate, param.Name, (FormParamDecode(param.Value)));
                        byte[] formitembytes = Encoding.UTF8.GetBytes(formitem);
                        memStream.Write(formitembytes, 0, formitembytes.Length);
                    }

                    memStream.Write(boundarybytes, 0, boundarybytes.Length);
                    memStream.Write(newlinebytes, 0, newlinebytes.Length);

                    string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: \"{2}\"\r\n\r\n";

                    foreach (SNSParameter param in files)
                    {
                        string name = param.Name;
                        string filePath = param.Value;
                        string file = Path.GetFileName(filePath);
                        string contentType = HttpUtil.GetContentType(file);

                        string header = string.Format(headerTemplate, name, file, contentType);
                        byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

                        memStream.Write(headerbytes, 0, headerbytes.Length);

                        var fileParam = param as SNSFileParameter;
                        if (fileParam != null && fileParam.Bytes.Length > 0)
                        {
                            memStream.Write(fileParam.Bytes, 0, fileParam.Bytes.Length);
                        }
                        else
                        {
                            var store = IsolatedStorageFile.GetUserStoreForApplication();
                            if (!store.FileExists(filePath))
                            {
                                throw new Exception("image file not exist!");
                            }

                            IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, store);

                            //var stream = store.OpenFile(filePath, FileMode.Open, FileAccess.Read);
                            //FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                            byte[] buffer = new byte[1024];
                            int bytesRead = 0;

                            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                memStream.Write(buffer, 0, bytesRead);
                            }
                            stream.Close();
                        }



                        memStream.Write(boundarybytes, 0, boundarybytes.Length);
                        //memStream.Write(newlinebytes, 0, newlinebytes.Length);

                    }
                    var bs = System.Text.Encoding.UTF8.GetBytes("--\r\n");
                    memStream.Write(bs, 0, bs.Length);
                    //webRequest.con = memStream.Length;
                    RequestState state = new RequestState();
                    state.cb = callback;
                    state.request = webRequest;

                    memStream.Position = 0;
                    byte[] bytes = new byte[memStream.Length];
                    memStream.Read(bytes, 0, bytes.Length);
                    memStream.Close();

                    state.PostData = bytes;
                    webRequest.BeginGetRequestStream(GetRequestStreamCallback, state);
                };
                allDone.WaitOne();
            }
            catch
            {
                return false;
            }
            finally
            {

            }

            return true;
        }

        private string FormParamDecode(string value)
        {
            int nCount = 0;
            for (int i = 0; i < value.Length; i++)
            {
                if (value[i] == '%')
                {
                    i += 2;
                }
                nCount++;
            }

            byte[] sb = new byte[nCount];

            for (int i = 0, index = 0; i < value.Length; i++)
            {
                if (value[i] != '%')
                {
                    sb.SetValue((byte)value[i], index++);
                }
                else
                {
                    StringBuilder sChar = new StringBuilder();
                    sChar.Append(value[i + 1]);
                    sChar.Append(value[i + 2]);
                    sb.SetValue(Convert.ToByte(sChar.ToString(), 16), index++);
                    i += 2;
                }
            }

            return System.Text.UTF8Encoding.UTF8.GetString(sb, 0, sb.Length);

        }

        private void FireCallback(RequestState state)
        {
            //call back
            if (state.cb != null)
            {
                state.cb(this, state.requestData.ToString());
            }
        }
    }
}
